#region File Description
//-----------------------------------------------------------------------------
// Fonts.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using System.Text;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
#endregion

namespace GameLib {
    /// <summary>
    /// Static storage of SpriteFont objects and colors for use throughout the game.
    /// </summary>
    static public class Fonts {
        #region Fonts


        private static SpriteFont normalFont;
        private static SpriteFont messageFont;
        private static SpriteFont typewriterFont;
        private static SpriteFont stencilFont;
        private static SpriteFont badaboomFont;
        private static SpriteFont pixelFont;

        public static SpriteFont Pixel {
            get { return pixelFont; }
        }

        public static SpriteFont Normal {
            get { return normalFont; }
        }

        public static SpriteFont Message {
            get { return messageFont; }
        }

        public static SpriteFont TypeWriter {
            get { return typewriterFont; }
        }

        public static SpriteFont Stencil {
            get { return stencilFont; }
        }

        public static SpriteFont BadaBoom {
            get { return badaboomFont; }
        }
        #endregion

        #region Initialization


        /// <summary>
        /// Load the fonts from the content pipeline.
        /// </summary>
        public static void LoadContent(ContentManager contentManager) {
            // check the parameters
            if (contentManager == null) {
                throw new ArgumentNullException("contentManager");
            }

            // load each font from the content pipeline
            normalFont = contentManager.Load<SpriteFont>("Fonts/Normal");
            messageFont = contentManager.Load<SpriteFont>("Fonts/Message");
            //typewriterFont = contentManager.Load<SpriteFont>("Fonts/TypeRa");
            //stencilFont = contentManager.Load<SpriteFont>("Fonts/Stencil");
            //badaboomFont = contentManager.Load<SpriteFont>("Fonts/Baddaboom");
            //pixelFont = contentManager.Load<SpriteFont>("Fonts/Volter");
        }


        /// <summary>
        /// Release all references to the fonts.
        /// </summary>
        public static void UnloadContent() {
            normalFont = null;
            messageFont = null;
            stencilFont = null;
            typewriterFont = null;
            badaboomFont = null;
            pixelFont = null;
        }


        #endregion


        #region Text Helper Methods


        /// <summary>
        /// Adds newline characters to a string so that it fits within a certain size.
        /// </summary>
        /// <param name="text">The text to be modified.</param>
        /// <param name="maximumCharactersPerLine">
        /// The maximum length of a single line of text.
        /// </param>
        /// <param name="maximumLines">The maximum number of lines to draw.</param>
        /// <returns>The new string, with newline characters if needed.</returns>
        public static string BreakTextIntoLines(string text,
            int maximumCharactersPerLine, int maximumLines) {
            if (maximumLines <= 0) {
                throw new ArgumentOutOfRangeException("maximumLines");
            }
            if (maximumCharactersPerLine <= 0) {
                throw new ArgumentOutOfRangeException("maximumCharactersPerLine");
            }

            // if the string is trivial, then this is really easy
            if (String.IsNullOrEmpty(text)) {
                return String.Empty;
            }

            // if the text is short enough to fit on one line, then this is still easy
            if (text.Length < maximumCharactersPerLine) {
                return text;
            }

            // construct a new string with carriage returns
            StringBuilder stringBuilder = new StringBuilder(text);
            int currentLine = 0;
            int newLineIndex = 0;
            while (((text.Length - newLineIndex) > maximumCharactersPerLine) &&
                (currentLine < maximumLines)) {
                text.IndexOf(' ', 0);
                int nextIndex = newLineIndex;
                while (nextIndex < maximumCharactersPerLine) {
                    newLineIndex = nextIndex;
                    nextIndex = text.IndexOf(' ', newLineIndex + 1);
                }
                stringBuilder.Replace(' ', '\n', newLineIndex, 1);
                currentLine++;
            }

            return stringBuilder.ToString();
        }


        /// <summary>
        /// Adds new-line characters to a string to make it fit.
        /// </summary>
        /// <param name="text">The text to be drawn.</param>
        /// <param name="maximumCharactersPerLine">
        /// The maximum length of a single line of text.
        /// </param>
        public static string BreakTextIntoLines(string text,
            int maximumCharactersPerLine) {
            // check the parameters
            if (maximumCharactersPerLine <= 0) {
                throw new ArgumentOutOfRangeException("maximumCharactersPerLine");
            }

            // if the string is trivial, then this is really easy
            if (String.IsNullOrEmpty(text)) {
                return String.Empty;
            }

            // if the text is short enough to fit on one line, then this is still easy
            if (text.Length <= maximumCharactersPerLine) {
                return text;
            }

            //text = text.Replace("\n"," ");
            text = text.Replace("  ","");

            // search for last ' ' before maxCharsInLine
            int breakPos = maximumCharactersPerLine;
            while ((breakPos > 0) && (text[breakPos] != ' '))
                breakPos--;

            // if none before, search for first ' ' after maxCharsInLine
            if (breakPos == 0) {
                breakPos = maximumCharactersPerLine + 1;
                while ((breakPos < text.Length) && (text[breakPos] != ' '))
                    breakPos++;

                // if none before or after, use entire string
                if (breakPos == text.Length)
                    return text;
            }

            return text.Substring(0, breakPos) + '\n' +
                BreakTextIntoLines(text.Substring(breakPos + 1), maximumCharactersPerLine);
        }


        /// <summary>
        /// Break text up into separate lines to make it fit.
        /// </summary>
        /// <param name="text">The text to be broken up.</param>
        /// <param name="font">The font used ot measure the width of the text.</param>
        /// <param name="rowWidth">The maximum width of each line, in pixels.</param>
        public static List<string> BreakTextIntoList(string text, SpriteFont font,
            int rowWidth) {
            // check parameters
            if (font == null) {
                throw new ArgumentNullException("font");
            }
            if (rowWidth <= 0) {
                throw new ArgumentOutOfRangeException("rowWidth");
            }

            // create the list
            List<string> lines = new List<string>();

            // check for trivial text
            if (String.IsNullOrEmpty("text")) {
                lines.Add(String.Empty);
                return lines;
            }

            // check for text that fits on a single line
            if (font.MeasureString(text).X <= rowWidth) {
                lines.Add(text);
                return lines;
            }

            // break the text up into words
            string[] words = text.Split(' ');

            // add words until they go over the length
            int currentWord = 0;
            while (currentWord < words.Length) {
                int wordsThisLine = 0;
                string line = String.Empty;
                while (currentWord < words.Length) {
                    string testLine = line;
                    if (testLine.Length < 1) {
                        testLine += words[currentWord];
                    }
                    else if ((testLine[testLine.Length - 1] == '.') ||
                        (testLine[testLine.Length - 1] == '?') ||
                        (testLine[testLine.Length - 1] == '!')) {
                        testLine += "  " + words[currentWord];
                    }
                    else {
                        testLine += " " + words[currentWord];
                    }
                    if ((wordsThisLine > 0) &&
                        (font.MeasureString(testLine).X > rowWidth)) {
                        break;
                    }
                    line = testLine;
                    wordsThisLine++;
                    currentWord++;
                }
                lines.Add(line);
            }
            return lines;
        }


        /// <summary>
        /// Returns a properly-formatted gold-quantity string.
        /// </summary>
        public static string GetGoldString(int gold) {
            return String.Format("{0:n0}", gold);
        }


        #endregion


        #region Drawing Helper Methods


        /// <summary>
        /// Draws text centered at particular position.
        /// </summary>
        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
        /// <param name="font">The font used to draw the text.</param>
        /// <param name="text">The text to be drawn</param>
        /// <param name="position">The center position of the text.</param>
        /// <param name="color">The color of the text.</param>
        public static void DrawCenteredText(SpriteBatch spriteBatch, SpriteFont font,
            string text, Vector2 position, Color color) {
            // check the parameters
            if (spriteBatch == null) {
                throw new ArgumentNullException("spriteBatch");
            }
            if (font == null) {
                throw new ArgumentNullException("font");
            }

            // check for trivial text
            if (String.IsNullOrEmpty(text)) {
                return;
            }

            // calculate the centered position
            Vector2 textSize = font.MeasureString(text);
            Vector2 centeredPosition = new Vector2(
                position.X - (int)textSize.X / 2,
                position.Y - (int)textSize.Y / 2);

            // draw the string
            spriteBatch.DrawString(font, text, centeredPosition, color, 0f,
                Vector2.Zero, 1f, SpriteEffects.None, 1f - position.Y / 720f);
            DrawOutlinedText(spriteBatch, font, text, centeredPosition, color, Color.Black, 2);
        }


        /// <summary>
        /// Draws a text with an outline.
        /// </summary>
        /// <param name="spriteBatch">Sprite batch that does the drawing</param>
        /// <param name="font">Font to use</param>
        /// <param name="text">Text to draw</param>
        /// <param name="position">Text position</param>
        /// <param name="textColor">Text color</param>
        /// <param name="outlineColor">Outline color</param>
        /// <param name="thickness">Outline thickness in pixels</param>
        public static void DrawOutlinedText(
            SpriteBatch spriteBatch, 
            SpriteFont font, 
            string text, 
            Vector2 position, 
            Color textColor, 
            Color outlineColor, 
            int thickness) {

            float px = position.X;
            float py = position.Y;
            for (float y = py - thickness; y <= py + thickness; y++) {
                for (float x = px - thickness; x <= px + thickness; x++) {
                    spriteBatch.DrawString(font, text, new Vector2(x, y), outlineColor);
                }
            }
            spriteBatch.DrawString(font, text, position, textColor);
        }


        #endregion
    }
}
